#include "GRO_Gui.h"
#include "GRO_Button.h"
#include "GRO_Panel.h"
#include "GRO_Checkbox.h"
#include "GRO_Spinner.h"

#include <iostream>
#include "SDL_image.h"
#include <unistd.h>
using namespace std;

#include "GRO_Renderer_Sprig.h"
#include "GRO_Font_NFont.h"

SDL_Surface* screen;
Uint8* keystates;

#include "sprig.h"
#include "NFont.h"
#include "SDL_ttf.h"

void setBool(bool* var, bool value)
{
    if(var != NULL)
        *var = value;
}

void testPrint()
{
    printf("test print\n");
    fflush(stdout);
}


inline SDL_Rect* CreateRect(Sint16 x, Sint16 y, Uint16 w, Uint16 h)
{
    SDL_Rect* r = new SDL_Rect;
    r->x = x;
    r->y = y;
    r->w = w;
    r->h = h;
    return r;
}

inline bool InRect(int x, int y, const SDL_Rect& rect)
{
    return (rect.x <= x && x <= rect.x + rect.w && rect.y <= y && y <= rect.y + rect.h);
}


inline void EnableUnicode(bool enable = 1)
{
    SDL_EnableUNICODE(enable);
}

inline void KeyRepeat(Uint16 delay = SDL_DEFAULT_REPEAT_DELAY, Uint16 interval = SDL_DEFAULT_REPEAT_INTERVAL)
{
    SDL_EnableKeyRepeat(delay, interval);
}

void printIt(const char* t)
{
    static int i = 0;
    printf("printIt: %d: %s\n", i++, t);
}


void start()
{
    using namespace GRO;
    SDL_Surface* BG = IMG_Load("../GUI_Screens/WindowsXP.jpg");
    
    
 
    EnableUnicode();
    KeyRepeat();
    
    
    Gui gui;
    
    gui.setRenderer(new GRO::Renderer_Sprig(screen));
    gui.init(screen->format, screen->w, screen->h);
    
    //gui->theme = createXPTheme();
    
    SDL_Surface* pointer0 = IMG_Load("../images/pointer.png");
    SDL_Surface* pointer1 = IMG_Load("../images/pointer1.png");
    SDL_Surface* pointer2 = IMG_Load("../images/pointer2.png");
    
    static_cast<PointerCursor*>(gui.cursors.front())->image = pointer0;
    //SDL_ShowCursor(0);
    //gui->cursors.clear();
    //static_cast<PointerCursor*>(gui->cursors.front())->image = IMG_Load("pointer.png");
    KeyboardSettings* keySettings = new KeyboardSettings;
    PointerCursor* keyboardCursor = new PointerCursor(keySettings, pointer1);
    keyboardCursor->gui = &gui;
    gui.cursors.push_back(keyboardCursor);
    
    SDL_JoystickEventState(SDL_ENABLE);
    JoystickSettings* joySettings = new JoystickSettings(SDL_JoystickOpen(0));
    PointerCursor* joystickCursor = new PointerCursor(joySettings, pointer2);
    joystickCursor->gui = &gui;
    gui.cursors.push_back(joystickCursor);
    
    /*joystickCursor = new PointerCursor(new JoystickSettings(SDL_JoystickOpen(1)), IMG_Load("pointer2.png"));
    joystickCursor->gui = gui;
    gui->cursors.push_back(joystickCursor);
    */
    
    
    NFont f1;
    TTF_Font* ttf = TTF_OpenFont("../fonts/FreeSans.ttf", 14);
    
    SDL_Color fgColor = {0, 0, 0, SDL_ALPHA_OPAQUE};
    f1.load(ttf, fgColor);
    f1.setDest(screen);
    
    TTF_CloseFont(ttf);
    
    
    
    //gui.fontMap = new FontMap;
    
    GRO_Font* font1 = new GRO_Font_NFont(&f1);
    GRO_FontID fontID = getFontMap()->add(font1);
    getFontMap()->setIndexedFont(0, fontID);
    
    
    NFont whiteFont;
    whiteFont.load(screen, NFont::verticalGradient(NFont::copySurface(f1.getSurface()), 0xffffff, 0x999999, 0));
    
    GRO_Font_NFont* font2 = new GRO_Font_NFont(&whiteFont);
    getFontMap()->setIndexedFont(1, getFontMap()->add(font2));
    
    
    
    bool createGui = true;
    if(createGui)
    {
        Panel* panel = new Panel(Dimensions(400, 400));
        panel->setName("main_panel");
        gui.add(panel);
        
        Widget* widget = new Text("Foods #1I Like#0:");
        panel->add(widget);
        // If text is editable, then the user could change the font...  
        // That is bad.  Maybe editable text should disable the font parsing.
        
        // TODO: It'd be nice to center each widget in its row...
        // Find the widget with the largest height to define the center?
         

        Checkbox* checkbox = new Checkbox(Dimensions(20, 20), true);
        panel->addToNewRow(checkbox);
     
        widget = new Text("Pizza");
        panel->add(widget);
        
        
        checkbox = new Checkbox(Dimensions(20, 20), false);
        panel->addToNewRow(checkbox);
     
        widget = new Text("Broccoli");
        panel->add(widget);
        
        
        Group* group = new Group(Dimensions(200, 200));
        group->setName("inner_group");
        panel->addToNewRow(group);
        
        Button* button;
        
        button = new Button(Dimensions(40, 30), "OK2");
        group->add(button);
        button = new Button(Dimensions(40, 30), "OK3");
        group->add(button);
        button = new Button(Dimensions(40, 30), "OK4");
        group->add(button);
        
        //widget = new Text("I like this one because:\n", font1);
        //dynamic_cast<Text*>(widget)->editable = true;
        //dynamic_cast<Text*>(widget)->textMax = 1000;
        //widget->area.w = 170;
        //widget->area.h = 400;
        
        //group->set(0, 0, widget);
        
        Spinner* spinner = new Spinner(Dimensions(20, 30));
        group->addToNewRow(spinner);
        
        Text* text = new Text;
        group->add(text);
        
        text->buffer.text = "#%";
        text->buffer.addVariable(new PrimitiveObjectString<int>(&spinner->value));
        text->refresh();
        
        spinner->refreshTextOnClick(text);
        
        button = new Button(Dimensions(40, 30), "OK");
        button->name = "OK";
        panel->addToNewRow(button);
        
        //panel->fitContents();
        
        gui.registerBeacon(button, "onClick", group, "toggleFolded");
        gui.registerBeacon(button, "onEnter", group, "unfold");
    
        gui.save("testsprig.xml");
    }
    else
        gui.load("testsprig.xml");
    
    printf("Size: %d\n", gui.widgets.size());
    
    Widget* w = gui.widgets.get("OK");
    Panel* p = static_cast<Panel*>(gui.widgets.get("main_panel"));
    Group* g = static_cast<Group*>(gui.widgets.get("inner_group"));
    
    //w->onHover.connect<void, const char*>(printIt, "Hover");
    w->onPress.connect<void, const char*>(printIt, "Press");
    w->onClick.connect<void, const char*>(printIt, "Click");
    w->onEnter.connect<void, const char*>(printIt, "Enter");
    w->onLeave.connect<void, const char*>(printIt, "Leave");
    w->onDrag.connect<void, const char*>(printIt, "Drag");
    
    
    w->onRelease.connect<void, const char*>(printIt, "Release");
    w->onDoubleClick.connect<void, const char*>(printIt, "DoubleClick");
    w->onScrollUp.connect<void, const char*>(printIt, "ScrollUp");
    w->onScrollDown.connect<void, const char*>(printIt, "ScrollDown");
    w->onMotion.connect<void, const char*>(printIt, "Motion");
    
    //w->onClick.connect(p, &Panel::close);
    std::vector<std::string> vs;
    //vs.push_back("true");
    //g->connectByName(w->onClick, "fold", vs);
    //g->connectByName("OK", "onClick", "toggleFolded", vs);
    //gui.registerBeacon("OK", "onClick", "inner_group", "toggleFolded");
    
    std::vector<std::string> vs2;
    
    //p->connectByName("OK", "onClick", "close", vs2);
    // The loader will just use widgetMap.get() for one and have the other from the current XML element.
    
    // onClick="main_panel.open()"
    // link="main_panel.close()"
    // link="checkbox.set(0)"
    // link="spinner.increase()"
    // link="spinner.decrease()"
    // link="text.refresh()"
    /*
    Beacon onPress;
    Beacon onRelease;
    Beacon onClick;
    Beacon onDoubleClick;
    Beacon onScrollUp;
    Beacon onScrollDown;
    Beacon onMotion;
    Beacon onDrag;
    Beacon onHover;
    Beacon onEnter;
    Beacon onLeave;*/
    
    SPG_EnableDirty(1);
    SPG_DirtyInit(64);
    
    
    
    SDL_FillRect(screen, NULL, 0x7171C6);
    SDL_Flip(screen);
    Uint32 frametime;
    
    float targetFps = 60;
    float waitTime = 1000.0f / targetFps;
    
    int mx = 0, my = 0;
    
    bool done = 0;
    
    // Add QUIT shortcut
    Shortcut* shortcut = new Shortcut(KMOD_CTRL, SDLK_q);
    shortcut->onExecute.connect<void, bool*, bool>(setBool, &done, true);
    gui.addShortcut(shortcut);
    
    
    // FIXME: NFont's setBaseline() and the ascent part of load() are broken...
    /*printf("f1: %d, %d\n", f1.getSurface()->w, f1.getSurface()->h);
    printf("f1: %d\n", f1.getBaseline());
    printf("f1: %d\n", f1.getAscent());
    printf("whiteFont: %d, %d\n", whiteFont.getSurface()->w, whiteFont.getSurface()->h);
    printf("whiteFont: %d\n", whiteFont.getBaseline());
    printf("whiteFont: %d\n", whiteFont.getAscent());*/
    
    
    SDL_Event event;
    int frameStart;
    while (!done)
    {
        frameStart = SDL_GetTicks();
        SDL_GetMouseState(&mx, &my);
        
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT)
                done = true;
            
            if(gui.event(event) != NULL)
                continue;
            

            if (event.type == SDL_KEYDOWN)
            {
                
            }
        }
        
        
        SPG_Draw(BG, screen, 0,0);
        
        gui.update();
        
        gui.draw();

        SPG_EnableDirty(0);
        
        if(SPG_DirtyEnabled())
        {
            SPG_DirtyTable* table = SPG_DirtyUpdate(screen);
            
            for(int i = 0; i < table->count; ++i)
            {
                SDL_FillRect(screen, &(table->rects[i]), 0x7171C6);
            }
            
            SPG_DirtySwap();
        }
        else
        {
            SDL_Flip(screen);
            SDL_FillRect(screen, NULL, 0x7171C6);
        }
        
        frametime = SDL_GetTicks() - frameStart;

        if (SDL_GetTicks() - frameStart < waitTime)
            SDL_Delay((int)(waitTime - frametime));

    }
    
    SDL_FreeSurface(f1.getSurface());
    
    SDL_FreeSurface(pointer0);
    SDL_FreeSurface(pointer1);
    SDL_FreeSurface(pointer2);
}







int main(int argc, char* argv[])
{
    char buff[] = "SDL_VIDEO_CENTERED=center";
    
    SDL_putenv(buff);
    
    screen = SPG_InitSDL(800, 600, 32, SDL_INIT_VIDEO | SDL_INIT_JOYSTICK, SDL_SWSURFACE);
    if(screen == NULL)
        return 0;
    
    int numJoy = SDL_NumJoysticks();
    if(numJoy > 0)
    {
        printf("%i joysticks were found.\n\n", numJoy);
        printf("The names of the joysticks are:\n");

        for( int i=0; i < numJoy; i++ )
        {
            printf("    %s\n", SDL_JoystickName(i));
        }
    }
    
    SDL_WM_SetCaption("Gui Test", NULL);
    
    keystates = SDL_GetKeyState(NULL);
    
    TTF_Init();
    
    srand(time(NULL));
    start();
    
    SDL_Quit();
    return 0;
}
